﻿//Copyright Notice:  ©2009 Microsoft Corporation.  All rights reserved.
using System;
using System.Text;
using System.Web;
using System.Security.Principal;
using System.Collections.ObjectModel;
using System.DirectoryServices;
using Microsoft.InformationSecurity.CISF.Security.AuthZServices;

//[assembly: CLSCompliant(true)]

namespace Microsoft.InformationSecurity.CISF.Security.Principal
{
    /// <summary>
    /// Creates a CISFPrincipal object based on WindowsIdentity current user.
    /// Gathers application defined roles for the identity.
    /// </summary>
    /// <remarks>
    /// If a GroupRoles object is not provided that has been instantiated,
    /// the user will only get the roles that are directly related to that user.
    /// </remarks>
    public class CISFPrincipal : IPrincipal
    {
        #region Private Variables
        private CISFIdentity identity;
        private DateTime timestamp;
        private ReadOnlyCollection<string> roles;

        #endregion 

        #region Constructor
        /// <summary>
        /// Instantiates a CISFPrincipal object. Does not load an identity or roles.
        /// </summary>
        public CISFPrincipal() 
        {
            timestamp = DateTime.Now;
        }

        /// <summary>
        /// Instantiates a CISFPrincipal object using provided identity and gathers 
        /// application defined roles for the passed in Identity.
        /// </summary>
        /// <param name="iIdentity">Identity object defining the user.</param>
        /// <param name="roles">A collection of roles associated to the user.</param>
        public CISFPrincipal(IIdentity identity, User user)
        {
            timestamp = DateTime.Now;
            LoadIdentity(identity, user);
        }

        #endregion

        #region Methods

        #region LoadIdentity
        /// <summary>
        /// Instantiates a CISFIdentity object from provided identity and gathers 
        /// application defined roles for the passed in Identity.
        /// </summary>
        /// <param name="identity">A generic IIdentity object.</param>
        public void LoadIdentity(IIdentity identity, User user)
        {
            if (this.identity != null)
                throw new InvalidOperationException("Identity is already loaded in CISFPrincipal object.");

            this.identity = new CISFIdentity(identity, user);

            //If the identity's name was not formatted correctly.
            if (String.IsNullOrEmpty(identity.Name))
            {
                this.identity = null;
                throw new ArgumentException("Invalid Identity name provided.  Unable to create a CISFPrincipal object.");
            }

            if (user != null)
                roles = new ReadOnlyCollection<string>(user.Roles);
        }

        #endregion

        #region IsInRole
        /// <summary>
        /// Determines if the principal belongs to the application role with the specified name.
        /// </summary>
        /// <param name="role">Name of the role.</param>
        /// <returns>true if user has the application role.</returns>
        public bool IsInRole(string role)
        {
            if (roles != null)
                return roles.Contains(role);
            else
                return false;
        }

        #endregion

        #endregion

        #region Properties

        #region CISFIdentity
        /// <summary>
        /// Gets the CISFIdentity object for this principal.
        /// </summary>
        public CISFIdentity CISFIdentity
        {
            get { return identity; }
        }

        #endregion

        #region Roles
        /// <summary>
        /// Gets the collection of application roles.
        /// </summary>
        public ReadOnlyCollection<string> Roles
        {
            get { return this.roles; }
        }

        #endregion

        #region Identity
        /// <summary>
        /// Gets the Identity object for this principal.
        /// </summary>
        public IIdentity Identity
        {
            get { return this.identity; }
        }

        #endregion

        #region Timestamp
        /// <summary>
        /// Gets or sets the Timestamp object used for determining when to refresh the principal.
        /// </summary>
        public DateTime Timestamp
        {
            get { return timestamp; }
            set { timestamp = value; }
        }

        #endregion

        #region Elapsed
        /// <summary>
        /// Gets the amount of time that has passed since the CISFPrincipal was instantiated
        /// or the Timestamp was last updated.
        /// </summary>
        public TimeSpan Elapsed
        {
            get { return DateTime.Now - timestamp; }
        }

        #endregion

        #endregion

    }
}
